package easy.trace.agent.plugin;

import easy.trace.agent.define.Instrumentation;
import easy.trace.agent.handle.ExceptionProtect;
import easy.trace.agent.util.CrossClassLoader;
import easy.trace.agent.util.PluginResourcesResolver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static easy.trace.agent.plugin.PluginDefine.OfficialComponent;

/**
 * @author easy
 */
public class PluginFinder {

    private PluginDefine pluginDefine = new PluginDefine();

    private ExceptionProtect callback;

    public PluginFinder(ExceptionProtect callback) {
        this.callback = callback;
    }

    /**
     * 载入配置文件插件
     */
    public void loadPlugin() {
        try {
            List<URL> urls = PluginResourcesResolver.getResources();
            for (URL resource : urls) {
                String[] pluginClass = readPluginLine(resource.openStream());
                for (String subClass : pluginClass) {
                    addPlugin(subClass);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            this.callback.handle(e);
        }
    }

    public List<PluginDefine.OfficialComponent> getPlugins() {
        return pluginDefine.getPlugin();
    }

    private static String[] readPluginLine(InputStream input) throws IOException {
        Set<String> pluginSet = new HashSet<>();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String pluginDefine;
            while ((pluginDefine = reader.readLine()) != null) {
                if (pluginDefine == null || pluginDefine.trim().length() == 0) {
                    continue;
                }
                pluginSet.add(pluginDefine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            input.close();
        }
        return pluginSet.toArray(new String[]{});
    }

    private void addPlugin(String pluginLine) {
        final String pluginInfo = "plugin";
        if (!pluginLine.contains(pluginInfo)) {
            return;
        }
        String[] pluginArr = pluginLine.split(".plugin=");
        final String pluginName = pluginArr[0];
        final String pluginClass = pluginArr[1];

        if (Objects.nonNull(pluginName) && pluginName.length() > 0) {
            OfficialComponent component = new OfficialComponent(2, pluginName);
            addOfficialComponent(component, pluginClass);
        }
    }

    private void addOfficialComponent(PluginDefine.OfficialComponent component, String pluginClass) {
        component.setInterceptorClass(pluginClass);
        Instrumentation instrumentationInstance = getInstrumentation(pluginClass);
        if (instrumentationInstance != null) {
            component.setInstrumentation(instrumentationInstance);
            pluginDefine.addPlugin(component);
        }
    }

    private static Instrumentation getInstrumentation(String pluginClass) {
        try {
            return (Instrumentation) CrossClassLoader.loadClass(pluginClass).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

}
